#include "Thread.hpp"
#include <iostream>
template <typename T>
class ThreadPool
{
private:
    // 同步与互斥接口
    void LockQueue(pthread_mutex_t &mutex) // 加锁
    {
        int n = pthread_mutex_lock(&mutex);
        assert(!n);
    }
    void UnlockQueue(pthread_mutex_t &mutex) // 解锁
    {
        int n = pthread_mutex_unlock(&mutex);
        assert(!n);
    }
    void ThreadSleep(pthread_cond_t &cond) // 使线程进入条件变量中等待
    {
        ++_waitnum;
        pthread_cond_wait(&cond, &_mutex);
        --_waitnum;
    }
    void WakeupAllThread(pthread_cond_t &cond) // 唤醒所有条件变量的接口
    {
        int n = pthread_cond_broadcast(&cond);
        assert(!n);
    }

    // 默认成员函数
    ThreadPool(int num = 3) : _threadnum(num), _is_running(true), _waitnum(0) // 单例模式下唯一能实例化对象的接口
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    ThreadPool(const ThreadPool &tp) = delete;
    ThreadPool &operator=(const ThreadPool &tp) = delete;

public:
    static ThreadPool<T> *GetInstance() // 获取/创建单例对象
    {
        if (_instance == nullptr)
        {
            pthread_mutex_lock(&_lock);
            if (_instance == nullptr)
            {
                _instance = new ThreadPool<T>;
                _instance->Start();
            }
            pthread_mutex_unlock(&_lock);
        }
        return _instance;
    }
    void WaitAll()    // 等待线程池中所有线程
    {
        for(auto& thread : _threads)
        {
            thread.Join();
        }
    }
    void HandlerTask() // 用于线程处理任务队列中的任务
    {
        while (true)
        {
            LockQueue(_mutex);
            while (_task_queue.empty() && _is_running) // while循环判断防止伪唤醒
            {
                // 任务队列中没任务且当前线程池正在运行
                ThreadSleep(_cond);
            }
            if (_task_queue.empty() && !_is_running)
            {
                // 任务队列中没任务且当前线程池不在运行
                UnlockQueue(_mutex);
                break;
            }

            // 任务队列中有任务，不管线程池在不在运行都要先处理完任务再说
            T t = _task_queue.front();
            _task_queue.pop();
            UnlockQueue(_mutex);
            t();
        }
    }
    void Enqueue(T t) // 主线程向任务队列中发任务的接口
    {
        LockQueue(_mutex);
        if (_is_running)
        {
            _task_queue.push(t);
            if (_waitnum > 0)
            {

                WakeupAllThread(_cond);
            }
        }
        UnlockQueue(_mutex);
    }

    void Start() // 启动线程池
    {
        for (size_t i = 0; i < _threadnum; ++i)
        {
            // 通过bind绑定this指针实现了一个类(Thread)调用另一个类(ThreadPool)的成员方法
            auto func = std::bind(&ThreadPool::HandlerTask, this);
            std::string name = "Thread-" + std::to_string(i + 1);
            _threads.push_back(Thread(func, name));
        }
        for (auto &thread : _threads)
        {
            thread.Start();
        }
    }
    void Exit() // 线程池退出
    {
        _is_running = false;
        WakeupAllThread(_cond);
    }

protected:
    // 线程池相关
    int _threadnum;               // 线程数量，固定！
    std::vector<Thread> _threads; // 管理线程池中的线程
    std::queue<T> _task_queue;    // 任务队列(共享资源)
    pthread_mutex_t _mutex;       // 保护任务队列的互斥锁
    pthread_cond_t _cond;         // 保护任务队列的条件变量
    bool _is_running;             // 线程池是否正在运行的标识符

    // 优化相关
    int _waitnum; // 记录条件变量下等待的线程个数，防止无效唤醒

    // 单例对象相关
    static ThreadPool<T> *_instance; // 懒汉模式，单例对象
    static pthread_mutex_t _lock;
};
template <typename T>
ThreadPool<T> *ThreadPool<T>::_instance = nullptr;

template <typename T>
pthread_mutex_t ThreadPool<T>::_lock = PTHREAD_MUTEX_INITIALIZER;